
package com.hlkj.pay.app.merchant.ext.impl.fuyou.handler;
/*
 * Hlpay-Plus aggregate payment system.
 * Copyright (c) 2024-2025 Hlpay Team Copyright has the right of final interpretation.
 */

import cn.hutool.core.bean.BeanUtil;
import com.hlkj.framework.common.pojo.CommonResult;
import com.hlkj.framework.common.util.json.JsonUtils;
import com.hlkj.pay.app.merchant.ext.dto.access.ChannelMerchantAccessAuthQueryContext;
import com.hlkj.pay.app.merchant.ext.dto.access.ChannelMerchantAccessContext;
import com.hlkj.pay.app.merchant.ext.dto.access.ChannelMerchantAccessQueryContext;
import com.hlkj.pay.app.merchant.ext.dto.access.ChannelMerchantTermContext;
import com.hlkj.pay.app.merchant.ext.impl.MerchantAccessCommonUtil;
import com.hlkj.pay.app.merchant.ext.impl.fuyou.constant.FuYouConstant;
import com.hlkj.pay.app.merchant.ext.impl.fuyou.dto.FuYouConfig;
import com.hlkj.pay.app.merchant.ext.impl.fuyou.dto.WechatAuthQueryResponse;
import com.hlkj.pay.app.merchant.ext.impl.fuyou.utils.SignUtils;
import com.hlkj.pay.common.CommonResultCode;
import com.hlkj.pay.dto.merchant.MerchantAccessDto;
import com.hlkj.pay.dto.merchant.MerchantWechatConfigDto;
import com.hlkj.pay.dto.merchant.ProviderChannelFeeConfigList;
import com.hlkj.pay.dto.pay.PayCommonAppDto;
import com.hlkj.pay.enums.MerchantEnum;
import com.hlkj.pay.enums.PayEnums;
import com.hlkj.pay.infrastructure.model.merchant.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 汇付 商户进件参数处理
 * 
 * @author HlpayTeam
 * @date 2024/09/26 12:02
 */
@Slf4j
public class FuYouMerchantParamsHandle extends FuYouMerchantCommonParamsHandle {

    private static Map<String, String> setCdMap = new HashMap<>();

    /**
     * 企业商户进件-新增参数组装
     *
     * @param channelMerchantAccessContext
     * @return
     */
    public static CommonResult<Map<String, Object>> merchantApplyParams(ChannelMerchantAccessContext channelMerchantAccessContext, FuYouConfig fuYouConfig) {
        Map<String, Object> params = new HashMap<>();
        MerchantAccessDto merchantAccessDto = channelMerchantAccessContext.getMerchantAccessDto();
        MerchantAccessBusinessDO merchantAccessBusiness = merchantAccessDto.getMerchantAccessBusiness();
        MerchantAccessInfoDO merchantAccessInfo = merchantAccessDto.getMerchantAccessInfo();
        List<ProviderChannelFeeConfigList> merchantFeeConfigList = channelMerchantAccessContext.getMerchantFeeConfigList();

        // 商户简称，不能有特殊字符，仅可包含汉字、数字、字母
        params.put("mchnt_shortname", merchantAccessBusiness.getShortName());
        MerchantAccessCertInfoDO merchantAccessLegal = merchantAccessDto.getMerchantAccessLegal();
        MerchantAccessLicenseDO merchantAccessLicense = merchantAccessDto.getMerchantAccessLicense();
        MerchantAccessCertInfoDO merchantAccessContact = merchantAccessDto.getMerchantAccessContact();
        MerchantAccessCardDO merchantAccessCard = merchantAccessDto.getMerchantAccessCard();
        MerchantEnum.MERCHANT_TYPE merchantType = MerchantEnum.MERCHANT_TYPE.from(merchantAccessInfo.getType());
        String companyType = "A";
        switch (merchantType) {
            case PERSONAL:
                // 商户全称，不能有特殊字符，仅可包含汉字、数字、字母 (需与营业执照一致，如遇提示重复，请在后面加数字1、2...，若为小微商户，请命名为 商户 xxx。)
                if (channelMerchantAccessContext.getNameCount() == null) {
                    params.put("mchnt_name", "商户 " + merchantAccessInfo.getName());
                }
                else {
                    params.put("mchnt_name", "商户 " + merchantAccessInfo.getName() + channelMerchantAccessContext.getNameCount());
                }
                params.put("real_name", merchantAccessLegal.getName());
                break;
            case COMPANY:
                if (channelMerchantAccessContext.getNameCount() == null) {
                    params.put("mchnt_name", merchantAccessInfo.getName());
                }
                else {
                    params.put("mchnt_name", merchantAccessInfo.getName() + channelMerchantAccessContext.getNameCount());
                }
                params.put("real_name", merchantAccessLicense.getName());
                companyType = companyType(merchantAccessInfo.getType(), merchantAccessLicense);

        }

        params.put("license_type", companyType);
        switch (companyType) {
            case "0":
            case "1":
            case "B":
                params.put("license_no", merchantAccessLicense.getLicenseCode());
                params.put("license_expire_dt", date(merchantAccessLicense.getLicenseEndDate()));
                break;
            case "A":
                params.put("license_no", merchantAccessLegal.getCertNo());
                params.put("license_expire_dt", date(merchantAccessLegal.getCertEndDate()));
                // params.put("acnt_nm", merchantAccessLegal.getName());
                params.put("acnt_artif_flag", "1");
                break;
            case "E":
                // 单位万
                params.put("start_funds", merchantAccessLegal.getCertNo());
                break;
        }
        params.put("certif_id", merchantAccessLegal.getCertNo());
        params.put("certif_id_expire_dt", date(merchantAccessLegal.getCertEndDate()));
        params.put("contact_person", merchantAccessContact.getName());
        params.put("contact_phone", merchantAccessBusiness.getServicePhone());
        params.put("contact_addr", merchantAccessBusiness.getAddress());
        params.put("contact_mobile", merchantAccessContact.getPhone());
        params.put("contact_email", merchantAccessContact.getOtherValue());
        params.put("business", merchantAccessBusiness.getWechatMcc());
        params.put("ali_mcc", merchantAccessBusiness.getAlipayMcc());
        params.put("city_cd", merchantAccessBusiness.getCityCode());
        params.put("county_cd", merchantAccessBusiness.getAreaCode());

        MerchantEnum.CARD_TYPE cardType = MerchantEnum.CARD_TYPE.from(merchantAccessCard.getType());
        switch (cardType) {
            case CORPORATE_ACCOUNT:
                params.put("acnt_type", "1");
                params.put("acnt_artif_flag", "1");
                // params.put("acnt_nm", merchantAccessLegal.getName());
                break;
            case PRIVATE_CORPORATE_ACCOUNT:
                params.put("acnt_type", "2");
                params.put("acnt_artif_flag", "1");
                params.put("acnt_contact_mobile", merchantAccessCard.getCardPhone());
                // params.put("acnt_nm", merchantAccessLegal.getName());
                break;
            case PRIVATE_NON_CORPORATE_ACCOUNT:
                params.put("acnt_type", "2");
                params.put("acnt_artif_flag", "0");
                params.put("acnt_contact_mobile", merchantAccessCard.getCardPhone());
                params.put("acnt_certif_tp", certType(merchantAccessCard.getCertType()));
                params.put("acnt_certif_id", merchantAccessCard.getCertNo());
                break;
            default:
        }

        // 1. 如果 license_type=A，acnt_nm=artif_nm 即小微商户身份证入网须入账法人
        // 2. 如果 acnt_type=2 且acnt_artif_flag=1，则 acnt_nm=artif_nm
        // 即对私且法人入账，则入账卡户名和法人姓名一致
        // 3. 如果 acnt_type=1 且acnt_artif_flag=1，则 acnt_nm=real_name
        // 即对公且法人入账，则入账卡户名和营业执照上商户名一致(营业执照上商户名指的是店铺名称)
        // if ("A".equals(params.get("license_type"))) {
        // params.put("acnt_nm", merchantAccessLicense.getName());
        // }
        // if ("2".equals(params.get("acnt_type")) &&
        // "1".equals(params.get("acnt_artif_flag"))) {
        // params.put("acnt_nm", merchantAccessLicense.getName());
        // }
        // if ("1".equals(params.get("acnt_type")) &&
        // "1".equals(params.get("acnt_artif_flag"))) {
        // params.put("acnt_nm", merchantAccessLicense.getName());
        // }
        params.put("acnt_nm", merchantAccessCard.getName());
        params.put("bank_type", merchantAccessCard.getBankCode());
        params.put("inter_bank_no", merchantAccessCard.getBranchCode());
        params.put("iss_bank_nm", merchantAccessCard.getBankName());

        params.put("acnt_no", merchantAccessCard.getCardNo());
        ProviderChannelFeeConfigList settleCycleConf = getSettleCycle(merchantFeeConfigList);
        if (MerchantEnum.SETTLE_CYCLE.D0.getPayWayCode().equals(settleCycleConf.getPayWayDO().getCode()) || MerchantEnum.SETTLE_CYCLE.D1.getPayWayCode().equals(settleCycleConf.getPayWayDO().getCode())) {
            params.put("settle_tp", "3");
            if (fuYouConfig.getAutoRateBase() == null) {
                return CommonResult.error(CommonResultCode.PARAMETER_MISSING.getCode(), "富友默认自动结算费率不存在");
            }
            String setCd = setCd(fuYouConfig.getAutoRateBase());
            if (!StringUtils.hasText(setCd)) {
                return CommonResult.error(CommonResultCode.PARAMETER_MISSING.getCode(), "富友默认自动结算费率扣率套餐代码无效");
            }
            params.put("settle_tp_cd", setCd);
        } else if (MerchantEnum.SETTLE_CYCLE.T1.getPayWayCode().equals(settleCycleConf.getPayWayDO().getCode())) {
            params.put("settle_tp", "1");
        }else if (MerchantEnum.SETTLE_CYCLE.MANUAL.getPayWayCode().equals(settleCycleConf.getPayWayDO().getCode())) {
            params.put("settle_tp", "5");
            if (fuYouConfig.getManualRateBase() == null) {
                return CommonResult.error(CommonResultCode.PARAMETER_MISSING.getCode(), "富友默认手动结算费率不存在");
            }
            String setCd = setCd(fuYouConfig.getManualRateBase());
            if (!StringUtils.hasText(setCd)) {
                return CommonResult.error(CommonResultCode.PARAMETER_MISSING.getCode(), "富友默认手动结算费率扣率套餐代码无效");
            }
            params.put("settle_tp_cd", setCd);
        }

        params.put("artif_nm", merchantAccessLegal.getName());
        params.put("acnt_certif_expire_dt", date(merchantAccessCard.getCertEndDate()));
        Map<Integer, List<ProviderChannelFeeConfigList>> feeConfigMap = merchantFeeConfigList.stream()
                .collect(Collectors.groupingBy(merchantFeeConfig -> merchantFeeConfig.getPayWayDO().getType()));

        List<ProviderChannelFeeConfigList> wechatFeeConfigList = feeConfigMap.get(PayEnums.PAY_TYPE.WECHAT.getCode());
        List<ProviderChannelFeeConfigList> alipayFeeConfigLists = feeConfigMap.get(PayEnums.PAY_TYPE.ALIPAY.getCode());
        if (!CollectionUtils.isEmpty(wechatFeeConfigList)) {
            ProviderChannelFeeConfigList providerChannelFeeConfigList = MerchantAccessCommonUtil.defaultFeeConfig(wechatFeeConfigList);
            if (providerChannelFeeConfigList != null) {
                String setCd = setCd(providerChannelFeeConfigList.getDefaultFeeConfigValue().getRateBase());
                if (!StringUtils.hasText(setCd)) {
                    return CommonResult.error(CommonResultCode.PARAMETER_MISSING.getCode(), "富友微信费率扣率套餐代码无效,支付代码为:" + providerChannelFeeConfigList.getPayWayDO().getName());
                }
                params.put("wx_flag", "1");
                params.put("wx_set_cd", setCd);
            }
        }
        else {
            params.put("wx_flag", "0");
        }
        if (!CollectionUtils.isEmpty(alipayFeeConfigLists)) {
            ProviderChannelFeeConfigList providerChannelFeeConfigList = MerchantAccessCommonUtil.defaultFeeConfig(alipayFeeConfigLists);
            if (providerChannelFeeConfigList != null) {
                String setCd = setCd(providerChannelFeeConfigList.getDefaultFeeConfigValue().getRateBase());
                if (!StringUtils.hasText(setCd)) {
                    return CommonResult.error(CommonResultCode.PARAMETER_MISSING.getCode(), "富友支付宝费率扣率套餐代码无效,支付代码为:" + providerChannelFeeConfigList.getPayWayDO().getName());
                }
                params.put("ali_flag", "1");
                params.put("ali_set_cd", setCd);
            }
        }
        else {
            params.put("ali_flag", "0");
        }
        params.put("has_reserve_acnt", "0");
        switch (merchantType) {
            case COMPANY:
                switch (cardType) {
                    case PRIVATE_CORPORATE_ACCOUNT:
                    case PRIVATE_NON_CORPORATE_ACCOUNT:
                        if(!companyType.equals("A")&&!companyType.equals("B")){
                            params.put("has_reserve_acnt", "1");
                            params.put("reserve_acnt_no", merchantAccessCard.getOfficialCardNo());
                            params.put("reserve_acnt_nm", merchantAccessCard.getOfficialName());
                            params.put("reserve_inter_bank_no", merchantAccessCard.getOfficialBranchCode());
                            params.put("reserve_iss_bank_nm", merchantAccessCard.getOfficialBankName());
                            params.put("reserve_bank_type", merchantAccessCard.getOfficialBankCode());
                        }
                        break;
                    default:

                }
                break;
        }
        params.put("contact_cert_no", merchantAccessContact.getCertNo());
        if (merchantAccessLicense != null) {
            params.put("license_start_dt", date(merchantAccessLicense.getLicenseBeginDate()));
            params.put("lic_regis_addr", merchantAccessLicense.getAddress());
        }
        params.put("card_start_dt", date(merchantAccessLegal.getCertBeginDate()));
        params.put("certif_phone", merchantAccessLegal.getPhone());
        params.put("certif_addr", merchantAccessLegal.getAddress());
        params.put("settle_tp", "3");
        // todo 测试环境写死
        if (channelMerchantAccessContext.isTest()) {
            params.put("settle_tp_cd", "M0000");
            params.put("wx_set_cd", "M0000");
            params.put("ali_set_cd", "M0000");
        }
        // params.put("inter_bank_no", "301290000007");
        return CommonResult.success(params);

    }

    private static ProviderChannelFeeConfigList getSettleCycle(List<ProviderChannelFeeConfigList> merchantFeeConfigList) {
        return merchantFeeConfigList.stream().filter(conf -> Objects.equals(conf.getPayWayDO().getType(), PayEnums.PAY_TYPE.FUNCTION.getCode())).findFirst().get();
    }

    /**
     * 查询参数解析
     *
     * @param response
     * @param channelMerchantAccessQueryContext
     */
    public static void merchantQueryParamsParse(String response, ChannelMerchantAccessQueryContext channelMerchantAccessQueryContext) {
        // 响应报文验签
        Map<String, String> resMap = JsonUtils.parseObject(response, Map.class);
        String retCode = resMap.get("ret_code");
        String retMsg = resMap.get("ret_msg");
        String insSt = resMap.get("insSt");
        if (FuYouConstant.REQUEST_SUCCESS.equals(retCode)) {
            if ("1".equals(insSt)) {
                channelMerchantAccessQueryContext.setAccessStatus(MerchantEnum.ACCESS_STATUS.WAIT_SETTING);
            }
        }
        else {
            channelMerchantAccessQueryContext.setProcessStatus(false);
        }
    }

    /**
     *
     * @param subMchId
     * @param domain
     * @param payCommonAppList
     * @return
     */
    public static Map<String, Object> wechatConfigSetParams(String subMchId, String domain, List<PayCommonAppDto> payCommonAppList) {
        Map<String, Object> params = new HashMap<>();
        if (CollectionUtils.isEmpty(payCommonAppList)) {
            return params;
        }
        List<Map<String, String>> configs = new ArrayList<>();
        payCommonAppList.stream().forEach(payCommonAppDO -> {
            Map<String, String> config = new HashMap<>();
            config.put("mchntCd", subMchId);
            config.put("subAppid", payCommonAppDO.getAppId());
            // config.put("jsapiPath", domain);
            configs.add(config);
        });
        params.put("configs", configs);
        return params;
    }

    /**
     *
     * @param subMchId
     * @param merchantWechatConfigDto
     * @return
     */
    public static Map<String, Object> wechatConfigSetParams(String subMchId, MerchantWechatConfigDto merchantWechatConfigDto) {
        Map<String, Object> params = new HashMap<>();
        List<Map<String, String>> configs = new ArrayList<>();
        Map<String, String> config = new HashMap<>();
        config.put("mchntCd", subMchId);
        config.put("subAppid", merchantWechatConfigDto.getAppId());
        if (StringUtils.hasText(merchantWechatConfigDto.getJsAPIPath())) {
            config.put("jsapiPath", merchantWechatConfigDto.getJsAPIPath());
        }
        configs.add(config);
        params.put("configs", configs);
        return params;
    }

    /**
     * 查询参数
     * 
     * @param subMchId
     * @return
     */
    public static Map<String, Object> merchantQueryParams(String subMchId) {
        Map<String, Object> params = new HashMap<>();
        List<Map<String, String>> configs = new ArrayList<>();
        Map<String, String> config = new HashMap<>();
        config.put("mchntCd", subMchId);
        configs.add(config);
        params.put("configs", configs);
        return params;
    }

    /**
     * 进件返回参数解析
     * 
     * @param resMap
     * @param channelMerchantAccessContext
     */
    public static void merchantApplyParamsParse(Map<String, Object> resMap, ChannelMerchantAccessContext channelMerchantAccessContext) {
        MerchantAccessInfoDO merchantAccessInfo = channelMerchantAccessContext.getMerchantAccessDto().getMerchantAccessInfo();
        String retCode = resMap.get("ret_code").toString();
        String retMsg = resMap.get("ret_msg").toString();
        if (FuYouConstant.REQUEST_SUCCESS.equals(retCode)) {
            String subMchId = resMap.get("fy_mchnt_cd").toString();
            merchantAccessInfo.setSubMchId(subMchId);
            channelMerchantAccessContext.setAuditStatus(MerchantEnum.CHANNEL_CONFIG_STATUS.SUBMIT);
            channelMerchantAccessContext.setAccessStatus(MerchantEnum.ACCESS_STATUS.WAIT_SET);
        }
        else {
            if(!StringUtils.hasText(merchantAccessInfo.getSubMchId())){
                channelMerchantAccessContext.setProcessStatus(Boolean.FALSE);
                channelMerchantAccessContext.setAccessStatus(MerchantEnum.ACCESS_STATUS.APPROVE_REFUSE);
                if (StringUtils.hasText(retMsg)) {
                    channelMerchantAccessContext.setRemark(retMsg);
                }
                else {
                    channelMerchantAccessContext.setRemark("富友个人开户返回错误信息为空,错误码为:" + retCode);
                }
            }else {
                channelMerchantAccessContext.setAuditStatus(MerchantEnum.CHANNEL_CONFIG_STATUS.SUBMIT);
                channelMerchantAccessContext.setAccessStatus(MerchantEnum.ACCESS_STATUS.WAIT_SET);
            }
        }
    }

    /**
     * 微信参数配置返回结果
     * 
     * @param response
     * @param channelMerchantAccessAuthQueryContext
     */
    public static void wxAuthQueryParamsParse(String response, ChannelMerchantAccessAuthQueryContext channelMerchantAccessAuthQueryContext) {
        // 响应报文验签
        Map<String, Object> resMap = SignUtils.xmlToObject(response);
        WechatAuthQueryResponse wechatAuthQueryResponse = BeanUtil.mapToBean(resMap, WechatAuthQueryResponse.class, true);

        String retCode = wechatAuthQueryResponse.getResult_code();
        String retMsg = wechatAuthQueryResponse.getResult_msg();
        List<MerchantAccessAuthDO> merchantAccessAuthList = new ArrayList<>();
        if (FuYouConstant.REQUEST_SUCCESS_STRING.equals(retCode)) {
            List<WechatAuthQueryResponse.ChannelInfo> authQueryResponseChannelInfos = wechatAuthQueryResponse.getChannel_infos();
            // 使用for循环进行迭代
            for (WechatAuthQueryResponse.ChannelInfo channelInfo : authQueryResponseChannelInfos) {
                MerchantAccessAuthDO merchantAccessAuthDO = new MerchantAccessAuthDO();
                // 获取并打印name和age
                // Object sub_mch_id = jsonObject.get("sub_mch_id");
                Integer authorize_state = channelInfo.getAuthorize_state();
                // Object reject_msgs = jsonObject.get("reject_msgs");
                String qr_code = channelInfo.getQr_code();
                // Object channel_name = jsonObject.get("channel_name");
                merchantAccessAuthDO.setSubMchId(channelInfo.getSub_mch_id());
                merchantAccessAuthDO.setStatus(authorize_state != null ? Integer.valueOf(authorize_state.toString()) : null);
                merchantAccessAuthDO.setRejectReason(channelInfo.getReject_msgs());
                if (StringUtils.hasText(qr_code)) {
                    if (qr_code.startsWith("http")) {
                        merchantAccessAuthDO.setAuthUrl(qr_code);
                    }
                    else {
                        try {
                            log.info("qr_code:{}", qr_code);
                            // qr_code = qr_code.replaceAll(" ", "+");
                            byte[] imageBytes = Base64.getDecoder().decode(qr_code);
                            merchantAccessAuthDO.setQrCodeArray(imageBytes);
                        }
                        catch (Exception e) {
                            log.error("base 64 图片数据解码错误");
                        }
                    }
                }
                merchantAccessAuthDO.setChannelJson(channelInfo.getChannel_name());
                merchantAccessAuthList.add(merchantAccessAuthDO);
            }
            channelMerchantAccessAuthQueryContext.setMerchantAccessAuthList(merchantAccessAuthList);
        }
        else {
            channelMerchantAccessAuthQueryContext.setProcessStatus(Boolean.FALSE);
            if (StringUtils.hasText(retMsg)) {
                channelMerchantAccessAuthQueryContext.setRemark(retMsg);
            }
            else {
                channelMerchantAccessAuthQueryContext.setRemark("富友微信认证信息返回错误信息为空,错误码为:" + retCode);
            }
        }
    }

    /**
     * 微信参数配置返回结果
     *
     * @param response
     * @param channelMerchantTermContext
     */
    public static void teamParamsParse(String response, ChannelMerchantTermContext channelMerchantTermContext) {
        // 响应报文验签
        Map<String, Object> resMap = SignUtils.xmlToObject(response);
        String retCode = resMap.get("ret_code").toString();
        String retMsg = resMap.get("ret_msg").toString();
        if (FuYouConstant.REQUEST_SUCCESS.equals(retCode)) {
            Object termId = resMap.get("term_id");
            if (termId != null) {
                channelMerchantTermContext.setTermId(termId.toString());
            }
        }
        else {
            channelMerchantTermContext.setProcessStatus(Boolean.FALSE);
            if (StringUtils.hasText(retMsg)) {
                channelMerchantTermContext.setRemark(retMsg);
            }
            else {
                channelMerchantTermContext.setRemark("富友新增终端信息返回错误信息为空,错误码为:" + retCode);
            }
        }
    }
}
